package com.glsc.ngateway.platform.service.it.networkAssets.dict;

import cn.hutool.core.lang.Pair;
import com.alibaba.excel.util.CollectionUtils;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.networkassets.dict.ItNetworkAssetsDict;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.networkassets.dict.ItNetworkAssetsDictField;
import com.glsc.ngateway.common.base.domain.mysql.gateway.platform.it.networkassets.dict.ItNetworkAssetsDictFieldValue;
import com.glsc.ngateway.common.api.platform.dto.it.networkassets.dict.ItNetworkAssetsDictDto;
import com.glsc.ngateway.common.api.platform.dto.it.networkassets.dict.ItNetworkAssetsDictFieldDto;
import com.glsc.ngateway.common.base.converter.platform.ItNetworkAssetsDictConverter;
import com.glsc.ngateway.common.base.converter.platform.ItNetworkAssetsDictFieldConverter;
import com.glsc.ngateway.common.base.enums.ItNetworkAssetsDictFieldTypeEnum;
import com.glsc.ngateway.common.base.exception.PlatformException;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.it.networkAssets.dict.ItNetworkAssetsDictFieldRepo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.it.networkAssets.dict.ItNetworkAssetsDictFieldValueRepo;
import com.glsc.ngateway.common.base.repo.mysql.gateway.platform.it.networkAssets.dict.ItNetworkAssetsDictRepo;
import com.glsc.ngateway.platform.utils.RandomIdUtils;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * IT网络资产字典Service
 * @author xuchang
 */
@Service
public class ItNetworkAssetsDictService {
    @Autowired
    ItNetworkAssetsDictRepo dictRepo;
    @Autowired
    ItNetworkAssetsDictFieldRepo fieldRepo;
    @Autowired
    ItNetworkAssetsDictFieldValueRepo valueRepo;

    /**
     * 查看
     */
    public List<ItNetworkAssetsDictDto> queryAll(ItNetworkAssetsDictDto param, boolean parentCodeIsNull) {
        param = Objects.isNull(param) ? new ItNetworkAssetsDictDto() : param;
        List<ItNetworkAssetsDict> pageRes = dictRepo.findAllByParam(param, parentCodeIsNull);
        //先填充数据
        fillData(pageRes);
        //再转DTO
        List<ItNetworkAssetsDictDto> dtoList = ItNetworkAssetsDictConverter.do2Dto(pageRes);
        //筛选value
        if (!Collections.isEmpty(param.getValueFilterList())) {
            Map<String, String> valFilterMap = param.getValueFilterList().stream()
                    .collect(Collectors.toMap(ItNetworkAssetsDictDto.ValueFilter::getParentValueCode
                            , ItNetworkAssetsDictDto.ValueFilter::getParentValue));
            dtoList.forEach(d -> {
                if (!Collections.isEmpty(d.getValueList())) {
                    d.setValueList(
                            d.getValueList().stream()
                                    .filter(v -> {
                                        for (Map.Entry<String, String> entry : v.entrySet()) {
                                            if (valFilterMap.containsKey(entry.getKey())
                                                    && valFilterMap.get(entry.getKey()).equals(entry.getValue())) {
                                                return true;
                                            }
                                        }
                                        return false;
                                    })
                                    .collect(Collectors.toList())

                    );
                }
            });
        }
        return dtoList;
    }

    /**
     * 填充children、fieldList、valueList、层级编号等信息
     */
    private void fillData(List<ItNetworkAssetsDict> dictList) {
        if (Collections.isEmpty(dictList)) {
            return;
        }
        for (int i = 0; i < dictList.size(); i++) {
            ItNetworkAssetsDict dict = dictList.get(i);
            Deque<ItNetworkAssetsDict> que = new ArrayDeque<>();
            que.addLast(dict);
            dict.setLevel(String.valueOf(i));
            //层次遍历
            while (!que.isEmpty()) {
                //每一层节点数
                int levelCount = que.size();
                for (int j = 0; j < levelCount; j++) {
                    ItNetworkAssetsDict first = que.pollFirst();
                    //添加children
                    List<ItNetworkAssetsDict> children = dictRepo.findAllByParentCode(first.getCode());
                    if (!Collections.isEmpty(children)) {
                        first.setChildren(children);
                        AtomicInteger cIdx = new AtomicInteger();
                        children.forEach(c -> {
                            c.setLevel(first.getLevel() + "-" + cIdx.getAndIncrement());
                            que.addLast(c);
                        });
                    }
                    //添加fieldList
                    first.setFieldList(fieldRepo.findAllByDictCode(first.getCode()));
                    //添加valueList
                    first.setValueList(valueRepo.findAllByDictCode(first.getCode()));
                }
            }
        }
    }

    /**
     * 删除字典， 将节点、字段、字段值全部做逻辑删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(@NotNull Long id) {
        ItNetworkAssetsDict parent = dictRepo.findById(id);
        if (Objects.isNull(parent)) {
            throw PlatformException.error("未找到字典", false, false);
        }
        //层次遍历,找出所有需要删除的节点
        List<ItNetworkAssetsDict> delChildrenDictList = new ArrayList<>();
        Queue<ItNetworkAssetsDict> que = new LinkedList<>();
        que.add(parent);
        while (!que.isEmpty()) {
            ItNetworkAssetsDict poll = que.poll();
            delChildrenDictList.add(poll);
            if (!Collections.isEmpty(poll.getChildren())) {
                que.addAll(poll.getChildren());
            }
        }
        //删除节点的code
        List<String> delDictCodeList = delChildrenDictList.stream().map(ItNetworkAssetsDict::getCode).collect(Collectors.toList());
        //删除节点的id
        List<Long> delIdList = delChildrenDictList.stream().map(ItNetworkAssetsDict::getId).collect(Collectors.toList());
        //删除节点
        dictRepo.deleteAllByIdIn(delIdList);
        //找到节点下所有字段
        List<ItNetworkAssetsDictField> fieldList = fieldRepo.findAllByDictCodeIn(delDictCodeList);
        if (!Collections.isEmpty(fieldList)) {
            List<String> delFieldCodeList = fieldList.stream().map(ItNetworkAssetsDictField::getCode).collect(Collectors.toList());
//            List<Long> delFieldIdList = fieldList.stream().map(ItNetworkAssetsDictField::getId).collect(Collectors.toList());
            //删除字段
            fieldRepo.deleteAllByDictCodeIn(delDictCodeList);
            //找到字段下所有值
            List<ItNetworkAssetsDictFieldValue> delValueList = valueRepo.findAllByDictCodeInAndDictFieldCodeIn(delDictCodeList, delFieldCodeList);
            if (!Collections.isEmpty(delValueList)) {
                List<Long> delValueIdList = delValueList.stream().map(ItNetworkAssetsDictFieldValue::getId).collect(Collectors.toList());
                //删除值
                valueRepo.deleteAllByIdIn(delValueIdList);
            }
        }
    }

    /**
     * 添加/修改
     */
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdate(@NotNull ItNetworkAssetsDictDto dictDto) {
        //先检查数据(逐层)
        checkDictLevelOrder(dictDto);
        //再添加数据(逐层)
        addOrUpdateLevelOrder(dictDto);
    }

    /**
     * 逐层检查数据
     */
    private void checkDictLevelOrder(ItNetworkAssetsDictDto dictDto) {
        Deque<ItNetworkAssetsDictDto> que = new ArrayDeque<>();
        que.addLast(dictDto);
        //层次遍历
        while (!que.isEmpty()) {
            ItNetworkAssetsDictDto poll = que.pollFirst();
            if (dictRepo.countByCodeAndIdNot(poll.getCode(), poll.getId()) > 0) {
                throw PlatformException.error(String.format("字典%s , code重复", poll.getCode()), false, false);
            }
            if (StringUtils.isBlank(poll.getLabelField())) {
                throw PlatformException.error(String.format("字典%s , 未选择展示字段", poll.getCode()), false, false);
            }
            if (StringUtils.isBlank(poll.getValueField())) {
                throw PlatformException.error(String.format("字典%s , 未选择参数字段", poll.getCode()), false, false);
            }
            //检查字段
            if (!Collections.isEmpty(poll.getFieldList())) {
                poll.getFieldList().forEach(f -> {
                    if (fieldRepo.countByFieldCodeAndIdNot(poll.getCode(), f.getCode(), f.getId()) > 0) {
                        throw PlatformException.error(String.format("字典%s的字段%s , code:%s 重复", poll.getDesc(), f.getDesc(), f.getCode()), false, false);
                    }
                });
            }
            //检查值
            if (!Collections.isEmpty(poll.getValueList())) {
                if (Collections.isEmpty(poll.getFieldList())) {
                    throw PlatformException.error("字典值不能为空", false, false);
                }
                //映射<字段code, <字段类型的长度, 字段类型的检查方法>>
                Map<String, Pair<Integer, ItNetworkAssetsDictFieldTypeEnum.ItNetworkAssetsDictFieldCheckMothod>> filedCheckMethodMap = poll.getFieldList()
                        .stream()
                        .collect(Collectors.toMap(ItNetworkAssetsDictFieldDto::getCode,
                                f -> new Pair<>(f.getLength(), ItNetworkAssetsDictFieldTypeEnum.valuesOf(f.getType()).getCheckMethod())));
                //遍历每一条数据
                poll.getValueList().forEach(valueObj -> {
                    valueObj.forEach((fieldCode, fieldVal) -> {
                        if (!filedCheckMethodMap.containsKey(fieldCode)) {
                            //不再校验字段是否匹配，场景：单独修改列时，单个列的数据无法进行校验
//                            throw PlatformException.error(String.format("字典值:【%s】:%s, 与字段不匹配", fieldCode, fieldVal));
                        } else if (Objects.isNull(fieldVal)) {
                            throw PlatformException.error(String.format("字典值: 【%s】, 不能为空", fieldCode), false, false);
                        } else {
                            //拿到Pair<字段类型的长度, 字段类型的检查方法>, 进行检查
                            Pair<Integer, ItNetworkAssetsDictFieldTypeEnum.ItNetworkAssetsDictFieldCheckMothod> pair = filedCheckMethodMap.get(fieldCode);
                            pair.getValue().check(fieldVal, pair.getKey());
                        }
                    });
                });
            }
            //将子节点放入队列
            if (!Collections.isEmpty(poll.getChildren())) {
                que.addAll(poll.getChildren());
            }
        }
    }

    /**
     * 逐层添加数据
     */
    private void addOrUpdateLevelOrder(ItNetworkAssetsDictDto dictDto) {
        Queue<ItNetworkAssetsDictDto> que = new LinkedList<>();
        que.add(dictDto);
        //层次遍历
        while (!que.isEmpty()) {
            ItNetworkAssetsDictDto pollDict = que.poll();
            //防止NPE
            pollDict.setFieldList(Collections.isEmpty(pollDict.getFieldList()) ? java.util.Collections.EMPTY_LIST : pollDict.getFieldList());
            pollDict.setValueList(Collections.isEmpty(pollDict.getValueList()) ? java.util.Collections.EMPTY_LIST : pollDict.getValueList());
            //添加或修改dict
            ItNetworkAssetsDict parent = dictRepo.save(Objects.requireNonNull(ItNetworkAssetsDictConverter.dto2Do(pollDict)));
            String parentCode = parent.getCode();
            //将子节点放入队列
            if (!Collections.isEmpty(pollDict.getChildren())) {
                pollDict.getChildren().forEach(c -> c.setParentCode(parentCode));
                que.addAll(pollDict.getChildren());
            }
            //添加或修改field
            List<ItNetworkAssetsDictField> oldFieldList = fieldRepo.findAllByDictCode(parentCode);
            if (!Collections.isEmpty(oldFieldList)) {
                //新数据中，哪些是旧的
                Set<Long> newFieldIds = pollDict.getFieldList().stream().map(ItNetworkAssetsDictFieldDto::getId).filter(Objects::nonNull).collect(Collectors.toSet());
                //对比新旧数据，删除不在新数据里的,
                List<Long> delFieldIds = oldFieldList.stream()
                        .map(ItNetworkAssetsDictField::getId)
                        .filter(i -> !newFieldIds.contains(i))
                        .collect(Collectors.toList());
                if (!Collections.isEmpty(delFieldIds)) {
                    fieldRepo.deleteAllByIdIn(delFieldIds);
                }
            }
            Map<String, ItNetworkAssetsDictFieldDto> fieldMap = new HashMap<>();
            //保存剩余数据
            pollDict.getFieldList().forEach(f -> {
                ItNetworkAssetsDictField fDo = ItNetworkAssetsDictFieldConverter.dto2Do(f);
                fDo.setDictCode(pollDict.getCode());
                fieldRepo.save(fDo);
                fieldMap.put(f.getCode(), f);
            });

            //添加或修改value
            //旧数据<recordId, <fieldCode, val>>
            Map<Long, Map<String, ItNetworkAssetsDictFieldValue>> oldValMap = valueRepo.findAllByDictCode(pollDict.getCode())
                    .stream()
                    .collect(Collectors.groupingBy(ItNetworkAssetsDictFieldValue::getRecordId, Collectors.toMap(ItNetworkAssetsDictFieldValue::getDictFieldCode, o -> o)));
            //删除被删除的数据
            if (!CollectionUtils.isEmpty(oldValMap)) {
                Set<Long> newRecordIds = pollDict.getValueList()
                        .stream()
                        .filter(valObj -> valObj.containsKey("id"))
                        .map(valObj -> Long.valueOf(valObj.get("id")))
                        .collect(Collectors.toSet());
                List<Long> delRecords = oldValMap.keySet().stream().filter(oId -> !newRecordIds.contains(oId)).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(delRecords)){
                    valueRepo.deleteAllByRecordIdIn(delRecords);
                }
            }
            //添加或修改
            pollDict.getValueList().forEach(valObj -> {
                Long recordId = valObj.containsKey("id") ? Long.valueOf(valObj.get("id")) : RandomIdUtils.randomId();
                valObj.remove("id");
                valObj.remove("fieldIndex");
                //添加或修改value
                valObj.forEach((fieldCode, fieldValue) -> {
                            if (fieldMap.containsKey(fieldCode)) {
                                valueRepo.save(
                                        ItNetworkAssetsDictFieldValue.builder()
                                                //如果是旧数据，用旧id
                                                .id(oldValMap.containsKey(recordId) ?
                                                        (oldValMap.get(recordId).containsKey(fieldCode) ?
                                                                oldValMap.get(recordId).get(fieldCode).getId()
                                                                : null)
                                                        : null)
                                                .dictFieldCode(fieldCode)
                                                .dictCode(pollDict.getCode())
                                                .value(fieldValue)
                                                .recordId(recordId)
                                                .build());
                            } else {
                                //不存在，做删除处理
                                valueRepo.deleteByDictFieldCodeAndRecordId(fieldCode, recordId);
                            }
                        }
                );
            });
        }
    }
}
